
using System;
using System.Collections.Generic;

namespace stefc.geo.lib
{

	public static class ColorMapFactory
    {
		public const Int32 Black = 0x00000000;
		public const Int32 White = 0x00FFFFFF;
		
		public static Int32 Red = ColorMapFactory.CreateRGB(255,0,0);
		public static Int32 Green = ColorMapFactory.CreateRGB(0,255,0);
		public static Int32 Blue = ColorMapFactory.CreateRGB(0,0,255);
		public static Int32 LightCoral = ColorMapFactory.CreateRGB(240, 128, 128);
		public static Int32 RoyalBlue = ColorMapFactory.CreateRGB(65,105,225);
		public static Int32 SkyBlue = ColorMapFactory.CreateRGB(135,206,235);
		public static Int32 DarkBlue = ColorMapFactory.CreateRGB(0,0,139);
			
        public static IList<Int32> CreateBlackWhite(int colorCount)
        {
			return ColorMapFactory.CreateLinearGradient(colorCount, ColorMapFactory.Black, ColorMapFactory.White);
		}

		public static IList<Int32> CreateLinearGradient(int colorCount, Int32 startColor, Int32 endColor)
        {
            IList<Int32> result = new List<Int32>(colorCount);
            
            for (int index = 0; index < colorCount; index++)
            {
                double percent = 1 - (double)index / (double)(colorCount-1);
                result.Add(CreateColor(startColor, endColor, percent));
            }

            return result;
        }

        public static IList<Int32> CreateLinearGradient(int colorCount, Int32 startColor, Int32 centerColor, Int32 endColor)
        {
            IList<Int32> result = new List<Int32>(colorCount);
            int mid = colorCount / 2;
            
            for (int index = 0; index < mid; index++)
            {
                double percent = 1 - (double)index / (double)(mid - 1);
                result.Add(CreateColor(startColor, centerColor, percent));
            }

            for (int index = 0; index < mid; index++)
            {
                double percent = 1 - (double)index / (double)(mid - 1);
                result.Add(CreateColor(centerColor, endColor, percent));
            }
            return result;
        }

        public static IList<Int32> CreateLava(int colorCount)
        {
            return CreateLinearGradient(colorCount, ColorMapFactory.Black, ColorMapFactory.LightCoral, ColorMapFactory.Black);
        }

        public static IList<Int32> CreateSkyBlue(int colorCount)
        {
            return CreateLinearGradient(colorCount, ColorMapFactory.RoyalBlue, ColorMapFactory.SkyBlue, ColorMapFactory.DarkBlue);
        }
        
        public static IList<Int32> CreateRGBW(int colorCount)
        {
        	List<Int32> result = new List<Int32>(colorCount);
        	int colors=colorCount/4;
        	result.AddRange(
        		CreateLinearGradient(colors,ColorMapFactory.White, ColorMapFactory.Red));
        	result.AddRange(
        		CreateLinearGradient(colors,ColorMapFactory.Red, ColorMapFactory.Green));
        	result.AddRange(
        		CreateLinearGradient(colors,ColorMapFactory.Green, ColorMapFactory.Blue));
        	result.AddRange(
        		CreateLinearGradient(colors,ColorMapFactory.Blue, ColorMapFactory.White));
        	return result;
        }
        
		private static IList<Int32> CreateLinearGradient(int colorCount, double[] weight, Int32[] colors)
        {
            IList<Int32> result = new List<Int32>(colorCount);
            
            double[] cummulated = new double[weight.Length];

            double total=0.0;
            for (int i = 0; i < weight.Length; i++)
            {
                cummulated[i] = total;
                total += weight[i];
            }

            double factor = (double) (colorCount-1)/total;

            for (int i = 0; i < weight.Length; i++)
            {
                Int32 startColor = colors[i * 2];
                Int32 endColor = colors[(i * 2) + 1];

                int len = (int) (factor * weight[i]);
                for (int index = 0; index < len; index++)
                {
                    double percent = 1 - (double)index / (double)(len- 1);
                    result.Add(CreateColor(startColor, endColor, percent));
                }
            }

            return result;
        }

        public static IList<Int32> CreateSpecial(int colorCount)
        {
            IList<Int32> result = CreateLinearGradient(colorCount, 
                new double[]{0.33,0.165,0.165,0.165,0.165,0.01}, 
                new Int32[] {
                    ColorMapFactory.Red, 	    
					ColorMapFactory.CreateRGB(255,253,0),
                    ColorMapFactory.CreateRGB(249,252,0), 
					ColorMapFactory.CreateRGB(6,131,0),
					ColorMapFactory.CreateRGB(0,125,6), 
					ColorMapFactory.CreateRGB(0,3,249),
					ColorMapFactory.CreateRGB(2,0,252), 
					ColorMapFactory.CreateRGB(73,0,133),
					ColorMapFactory.CreateRGB(79,3,133), 
					ColorMapFactory.CreateRGB(238,130,238),
					ColorMapFactory.Black, 	ColorMapFactory.Black});
			
			return result;
        }
        
		private static Int32 CreateColor(Int32 startColor, Int32 endColor, double percent)
        {
			byte sr = (byte)((startColor & 0x00FF0000) >> 16); 
			byte sg = (byte)((startColor & 0x0000FF00) >> 8); 
			byte sb = (byte)(startColor & 0x000000FF);
			
			byte er = (byte)((endColor & 0x00FF0000) >> 16); 
			byte eg = (byte)((endColor & 0x0000FF00) >> 8); 
			byte eb = (byte)(endColor & 0x000000FF);
			
			double r = (sr * percent) + (er * (1 - percent));
			double g = (sg * percent) + (eg * (1 - percent));
			double b = (sb * percent) + (eb * (1 - percent));
			return (Int32)(r) << 16 | (Int32)(g) << 8 | (Int32)(b);
		}
		
		private static Int32 CreateRGB(byte r, byte g, byte b)
		{
			return (Int32)(r) << 16 | (Int32)(g) << 8 | (Int32)(b);
		}
		
    }
}
